import { app, shell, BrowserWindow, ipcMain, Tray, buildFromTemplate, Menu } from 'electron'
import { join } from 'path'
import { electronApp, optimizer, is } from '@electron-toolkit/utils'
import icon from '../../resources/icon.ico?asset'
import store from './store'

import { closeWs, initWs } from './wsClient'
import { getUserEmailList, getUserSetting, saveUserSetting, updateContactNoReadCount } from './db/models/UserSettingModel'
import { clearNoReadCount, delChatSession, getChatSessionUser, getChatSessionUserList, setChatSessionTop, updateChatSessionStatus, updateChatSessionUser, updateContactName } from './db/models/ChatSessionUserModel'
import { getChatMessageList, saveChatMessage, updateChatMessage } from './db/models/ChatMessageModel'
import { changeFileFolder, closeServer, createAvatarCover, downloadUpdate, openFileFolder, saveAndUploadFile, saveAs, saveClipboardFile } from './file'
import { delWindow, getWindow, setWindow } from './windowProxy'

const NODE_ENV = process.env.NODE_ENV
const loginWidth = 450;
const loginHeight = 344;
const registerHeight = 450;

/* 开启新窗口 */
const openWindow = ({ windowId, title = "R-Chat", path, width = 800, height = 550, data }) => {
  // 先看window是否已经存在
  let window = getWindow(windowId)
  if (!window) {
    // 创建新窗口
    window = new BrowserWindow({
      width: width,
      height: height,
      fullscreenable: false,
      fullscreen: false,
      maximizable: false,
      autoHideMenuBar: true,
      titleBarStyle: 'hidden', /* 隐藏头部的条条 */
      resizable: false, /* 不允许拖动大小 */
      frame: true,
      transparent: true,
      hasShadow: false,
      icon: icon,
      webPreferences: {
        preload: join(__dirname, '../preload/index.js'),
        sandbox: false
      }
    })

    setWindow(windowId, window)
    window.setMinimumSize(600, 450)

    if (is.dev && process.env['ELECTRON_RENDERER_URL']) {
      // 开发是浏览器路由
      window.loadURL(`${process.env['ELECTRON_RENDERER_URL']}/index.html#${path}`)
    } else {
      // 打包后是使用的文件路由
      window.loadFile(join(__dirname, '../renderer/index.html'), { hash: `${path}` })
    }

    if (NODE_ENV === 'development') {
      window.webContents.openDevTools();
    }

    window.on('ready-to-show', () => {
      window.setTitle(title)
      window.show()
    })

    // 发送通信让对应的渲染进程初始化页面
    window.on('show', () => {
      setTimeout(() => {
        // 把serverPort也传过去，因为新窗口的pinia和原来的主窗口不同步，主窗口存的serverPort新窗口拿不到，只能通过主进程传递过去
        data.serverPort = store.getUserData("serverPort")
        window.webContents.send('newWindowInit', data)
      }, 500)  // 延迟500ms后再传递数据
    })

    window.on('closed', () => {
      delWindow(windowId)
    })
  } else {
    window.show()
    window.setSkipTaskbar(false)
    window.webContents.send('newWindowInit', data)
  }
}

function createWindow() {
  // Create the browser window.
  const mainWindow = new BrowserWindow({
    width: loginWidth,
    height: loginHeight,
    show: false,
    autoHideMenuBar: true,
    titleBarStyle: 'hidden', /* 隐藏头部的条条 */
    resizable: false, /* 不允许拖动大小 */
    frame: true,
    transparent: true,
    icon: icon,
    webPreferences: {
      preload: join(__dirname, '../preload/index.js'),
      sandbox: false
    }
  })

  // 把主窗口管理起来
  setWindow("main", mainWindow)

  /* 主进程接收到preload发送的注册/登录状态改变的消息，将窗口变高以适应增加的控件大小（防止滚动条出现） */
  ipcMain.on("loginOrRegisterSwitch", (event, isLogin) => {
    // console.log("isLogin changed to: ", isLogin)
    mainWindow.setResizable(true);
    const h = isLogin ? loginHeight : registerHeight
    mainWindow.setMaximumSize(loginWidth, h);
    mainWindow.setMinimumSize(loginWidth, h);
    mainWindow.setSize(loginWidth, h);
    mainWindow.center();
    mainWindow.setResizable(false)
  })

  /* 打开聊天窗口 */
  ipcMain.handle("openChat", async (event, config) => {
    // 隐藏窗口
    mainWindow.setOpacity(0)
    // 设置窗口大小和位置
    mainWindow.setResizable(true);
    mainWindow.setMaximizable(true);
    mainWindow.setMinimumSize(800, 600);
    mainWindow.setMaximumSize(2000, 1400);
    mainWindow.setSize(1000, 700);
    mainWindow.center();
    setTimeout(() => {
      // 显示窗口
      mainWindow.setOpacity(1)
    }, 200)

    // 保存用户信息
    store.setUserId(config.userId);
    store.setUserData("token", config.token);
    // 保存用户信息到本地数据库（还在store里存了fileFolder和serverPort）
    await saveUserSetting(config);

    // 初始化ws连接，接收并处理完成WS_INIT通知
    await initWs(config, event.sender)

    if (config.admin) {
      // 管理员窗口
      contextMenu.unshift({
        label: '管理后台',
        click() {
          openWindow({
            windowId: "admin",
            title: '管理后台',
            path: '/admin',
            width: config.screenWidth * 0.8,
            height: config.screenHeight * 0.8,
            data: {
              token: config.token
            }
          })
        }
      })

    }
    // 添加用户信息到托盘菜单
    contextMenu.unshift({
      label: '用户: ' + config.nickName,
      click() {
      }
    })
    tray.setContextMenu(Menu.buildFromTemplate(contextMenu)) // 重新设置托盘右键菜单
  })

  /* 托盘 */
  const tray = new Tray(icon)
  // 托盘右键菜单
  const contextMenu = [
    {
      label: '退出R-Chat',
      click() {
        app.quit()
      }
    }
  ]
  const menu = Menu.buildFromTemplate(contextMenu)  // 设置托盘右键菜单
  tray.setToolTip('R-Chat') // 托盘提示
  tray.setContextMenu(menu) // 设置托盘右键菜单
  tray.on('click', () => {
    mainWindow.setSkipTaskbar(false)
    mainWindow.show()
  })

  /* 窗口标题栏操作 */
  ipcMain.on("winTitleOp", (event, { action, data }) => {
    // 因为不知道是哪个窗口发送的关闭信息（可以是管理窗口，打开的图片视频窗口等），所以需要获取窗口
    const win = BrowserWindow.fromWebContents(event.sender)
    // console.log("action: ", action, " data: ", data, "win: ", win)
    switch (action) {
      case 'minimize': {
        win.minimize()
        break
      }
      case 'maximize': {
        win.maximize()
        break
      }
      case 'unmaximize': {
        win.unmaximize()
        break
      }
      case 'close': {
        if (data.closeType == 0) {
          // 直接关闭窗口
          win.close()
        }
        else {
          // 最小化到托盘
          win.setSkipTaskbar(true)
          win.hide()
        }
        break
      }
      case 'top': {
        win.setAlwaysOnTop(data.isTop)
        break
      }
    }
  })

  ipcMain.on('reLogin', (event, data) => {
    // 隐藏窗口
    mainWindow.setOpacity(0)
    // 大小改为登录窗口的大小
    mainWindow.setResizable(true);
    mainWindow.setMaximumSize(loginWidth, loginHeight);
    mainWindow.setMinimumSize(loginWidth, loginHeight);
    mainWindow.setSize(loginWidth, loginHeight);
    mainWindow.center();
    mainWindow.setResizable(false)
    setTimeout(() => {
      // 显示窗口
      mainWindow.setOpacity(1)
    }, 200)
    // 关闭ws连接
    closeWs();
    // 关闭本地服务器
    closeServer();
    // 去除托盘中的用户信息
    contextMenu.shift()
    tray.setContextMenu(Menu.buildFromTemplate(contextMenu))
    // 发送消息通知主窗口改变为登录窗口
    event.sender.send('reLogin', data)
  })

  ipcMain.on('setLocalStore', (event, data) => {
    store.setData(data.key, data.value)
    // console.log(store.getData(data.key))
  })

  ipcMain.handle('getLocalStore', (event, key) => {
    return store.getData(key);
  })

  ipcMain.handle('getChatSessionUserList', (event, data) => {
    return getChatSessionUserList();
  })

  ipcMain.on('setChatSessionTop', async (event, { contactId, topType }) => {
    await setChatSessionTop(contactId, topType);
  })

  ipcMain.on('delChatSession', async (event, contactId) => {
    await delChatSession(contactId);
  })

  ipcMain.handle('getChatMessageList', (event, data) => {
    return getChatMessageList(data.sessionId, data.pageNo, data.maxMessageId);
  })

  ipcMain.on('saveChatMessage', async (event, data) => {
    // 保存聊天消息
    await saveChatMessage(data);
    // 更新会话消息
    await updateChatSessionUser(store.getUserData("currentSessionId"), data)
    // 保存文件的操作
    // console.log("data: ", data)
    if (data.messageType == "MEDIA" || data.messageType == 1) { // messageType可能在上面的saveChatMessage里改了（
      await saveAndUploadFile(data.messageId, data.filePath, data.fileType)
      // 本地保存完毕之后更新发送的这条消息的状态为已发送
      await updateChatMessage({ sendStatus: 1 }, { messageId: data.messageId })
      // 通知渲染进程文件上传完毕了
      event.sender.send('fileUploadDone', { messageId: data.messageId })
    }
  })

  ipcMain.on('saveAs', async (event, data) => {
    await saveAs(data)
  })

  ipcMain.on('setSessionInfo', async (event, data) => {
    if (data.sessionId) {
      store.setUserData('currentSessionId', data.sessionId)
    } else {
      store.setUserData('currentSessionId', '')
    }
    // console.log("set currentSessionId: ", data.sessionId)
    if (data.contactId) {
      await clearNoReadCount(data.contactId)
    }
  })

  ipcMain.handle('createAvatarCover', (event, path) => {
    return createAvatarCover(path)
  })

  ipcMain.on('openMediaDetailWindow', (event, data) => {
    openWindow(data)
  })

  ipcMain.handle('saveClipboardFile', (event, data) => {
    return saveClipboardFile(data)
  })

  ipcMain.handle('getUserSetting', (event, data) => {
    return getUserSetting()
  })

  ipcMain.on('updateContactNoReadCount', async (event, data) => {
    await updateContactNoReadCount(data)
  })

  ipcMain.on('openFileFolder', async (event, data) => {
    await openFileFolder();
  })

  ipcMain.handle('changeFileFolder', async (event, data) => {
    return changeFileFolder()
  })

  ipcMain.handle('reloadChatSession', async (event, contactId) => {
    await updateChatSessionStatus(contactId, 1)
    return getChatSessionUser(contactId);
  })

  ipcMain.on('downloadUpdate', (event, data) => {
    downloadUpdate(data)
  })

  ipcMain.on('openUrl', (event, url) => {
    shell.openExternal(url)
  })

  ipcMain.handle('getUserEmailList', (event, data) => {
    return getUserEmailList()
  })

  mainWindow.on('ready-to-show', () => {
    mainWindow.setTitle('R-Chat')
    mainWindow.show()
  })

  mainWindow.webContents.setWindowOpenHandler((details) => {
    shell.openExternal(details.url)
    return { action: 'deny' }
  })

  // HMR for renderer base on electron-vite cli.
  // Load the remote URL for development or the local html file for production.
  if (is.dev && process.env['ELECTRON_RENDERER_URL']) {
    mainWindow.loadURL(process.env['ELECTRON_RENDERER_URL'])
  } else {
    mainWindow.loadFile(join(__dirname, '../renderer/index.html'))
  }
}

// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.whenReady().then(() => {
  // Set app user model id for windows
  electronApp.setAppUserModelId('com.electron')

  // Default open or close DevTools by F12 in development
  // and ignore CommandOrControl + R in production.
  // see https://github.com/alex8088/electron-toolkit/tree/master/packages/utils
  app.on('browser-window-created', (_, window) => {
    optimizer.watchWindowShortcuts(window)
  })

  createWindow()

  app.on('activate', function () {
    // On macOS it's common to re-create a window in the app when the
    // dock icon is clicked and there are no other windows open.
    if (BrowserWindow.getAllWindows().length === 0) createWindow()
  })
})

// Quit when all windows are closed, except on macOS. There, it's common
// for applications and their menu bar to stay active until the user quits
// explicitly with Cmd + Q.
app.on('window-all-closed', () => {
  if (process.platform !== 'darwin') {
    app.quit()
  }
})

// In this file you can include the rest of your app"s specific main process
// code. You can also put them in separate files and require them here.
